/*
Class: Ptr
Template: class _Ty
Version: 1.10.1.27
Author: NianchenDeng
Date: 2010.1.27
Purpose: Encapsulate C/C++ pointer so the programmers didn't need to
         worry whether the content allocated by new operator has been
         deleted or not. Also they needn't worry whether the content
         the pointer pointing to is valid. It would never be
         dangling pointer.
Usage: Construct a Ptr object with a pointer whose content is allocated
       by new operator. The content can be both an item or an array.
       Then you can use it just like normal C/C++ pointer.
       Operators like ->, * and [](If array) is supported.
       the pointer is also copyable.
       If you do not want to use it and want to release the memory
       manually, simply assign NULL to it. The memory will be recycled
       when there are no pointers pointing to it.
NOTE: You should not construct a Ptr with a invalid pointer
      or a pointer pointing to content in running stack.
      This will cause a runtime error.
      You should not construct a Ptr with a pointer whose content is
      allocated by malloc function. This will cause unpredictable result.
Thread-Safe: the class is not thread-safe.
*/
#pragma once
#include <malloc.h>

#define NULL 0
#define EMPTY_PTR -1
#define OUT_OF_RANGE -2

#ifndef uint
#define uint unsigned int
#endif


template< class _Ty >
class Ptr
{
private:
  typedef Ptr< _Ty > _My;
  _Ty* _Ptr;
  uint* _Ref_Num_P;
  bool _ref_incr ();
  bool _ref_decr ();
  void _release ();
public:
  Ptr ();
  Ptr (_Ty* const new_ptr);
  Ptr (const _My& right);
  ~Ptr ();

  _My& operator= (const _My& right);
  _Ty* operator-> () const;
  _Ty& operator[] (uint index) const;
  _Ty& operator* () const;
  operator _Ty* () const;
};

// ========================================================================
// Constructors & Destructor
// ========================================================================

template< class _Ty >
Ptr< _Ty >::Ptr () : _Ptr (NULL), _Ref_Num_P (NULL) {}

template< class _Ty >
Ptr< _Ty >::Ptr (_Ty* const new_ptr) : _Ptr (new_ptr)
{
  if (_Ptr) _Ref_Num_P = new uint (1);
  else _Ref_Num_P = NULL;
}

template< class _Ty >
Ptr< _Ty >::Ptr (const Ptr< _Ty >& right)
: _Ptr (right._Ptr), _Ref_Num_P (right._Ref_Num_P)
{
  _ref_incr ();
}

template< class _Ty >
Ptr< _Ty >::~Ptr ()
{
  _release ();
}

// ========================================================================
// Operator Functions
// ========================================================================

template< class _Ty >
Ptr< _Ty >& Ptr<_Ty>::operator= (const _My& right)
{
  _release ();
  _Ptr = right._Ptr;
  _Ref_Num_P = right._Ref_Num_P;
  _ref_incr ();
  return *this;
}

// Throw EMPTY_PTR when it points to NULL
template< class _Ty >
_Ty* Ptr< _Ty >::operator-> () const
{
  if (!_Ptr)
    throw (EMPTY_PTR);
  return _Ptr;
}

// Throw EMPTY_PTR when it points to NULL
// Throw OUT_OF_RANGE when index is too large
template< class _Ty >
_Ty& Ptr< _Ty >::operator[] (uint index) const
{
  if (!_Ptr)
    throw (EMPTY_PTR);
  if (_msize ((void*)_Ptr) / sizeof (_Ty) <= index)
    throw (OUT_OF_RANGE);
  return _Ptr[index];
}

template< class _Ty >
_Ty& Ptr< _Ty >::operator* () const
{
  return *_Ptr;
}


template< class _Ty >
Ptr<_Ty>::operator _Ty* () const
{
  return _Ptr;
}

// ========================================================================
// Private Functions
// ========================================================================
template< class _Ty >
void Ptr< _Ty >::_release ()
{
  _ref_decr ();
  if (!_Ref_Num_P && _Ptr)
  {
    if (_msize ((void*)_Ptr) / sizeof (_Ty) == 1)
      delete _Ptr;
    else
      delete[] _Ptr;
  }
  _Ref_Num_P = NULL;
  _Ptr = NULL;
}

template< class _Ty >
bool Ptr< _Ty >::_ref_incr ()
{
  if (_Ref_Num_P)
  {
    ++(*_Ref_Num_P);
    return true;
  }
  return false;
}

template< class _Ty >
bool Ptr< _Ty >::_ref_decr ()
{
  if (_Ref_Num_P)
  {
    --(*_Ref_Num_P);
    return true;
  }
  return false;
}